#ifndef __IOMANGER_H_
#define __IOMANGER_H_

/************************************************
 * Iomanger 继承于 [Scheduler] [TimerManger]
 * 
 * Scheduler只负责从任务队列中取出任务执行
 * Iomanger用于管理任务，什么时候放入scheduler任务队列中去执行
 * 如，IO事件read/定时任务时间发生后，Iomanger才会将相应的回调函数放入scheduler队列，scheduler调度一个线程去执行
 * 
 * 支持功能：
 * -event事件触发，event_loop(epoll_wait)
 * 
 * 
 * epoll: IO多路复用技术，idle函数会陷入epoll_wat
 * 
 * 
 * Eventctx :    事件对应的回调函数或者fiber
 *    |
 * FdContext   : 一个文件描述符包含两个事件Eventctx，读or写
 *    |
 *    |-triggerEvent：读/写事件被触发，将对应Eventctx放入到sched队列，即将执行
 *
 * 
 * IOmanger
 *    |
 *    |-contextResize(): 调整m_fdContexts数组大小
 * 
 * 
 * m_fdContexts: vector<FdContext*>, 容器，下标代表fd, 存储与fd对应的FdContext
 * m_pipefd:     用于手动唤醒epoll_wait
 * 
 * 
 * refenrence:
 * 深入 C++ 回调 https://bot-man-jl.github.io/articles/?post=2019/Inside-Cpp-Callback 
 * 彻底搞懂epoll高效运行的原理 https://cloud.tencent.com/developer/article/1488129
*************************************************/
#include <memory>
#include <sys/epoll.h>
#include <assert.h>
#include <vector>

#include "scheduler.h"
#include "thread.h"
#include "fiber.h"
#include "timer.h"



namespace learnco
{

class IOmanger : public Scheduler, public TimerManger {
    
public:
    typedef std::shared_ptr<IOmanger> ptr;
    typedef RWMutex RWMutexType;

    enum Event
    {
        NONE = 0x000,
        READ = 0x001,  //EPOLLIN
        WRITE = 0x004, //EPOLLOUT
        EPOLLET
    };

private:
    struct FdContext
    {
        typedef Mutex MutexType;
        struct Eventctx
        {
            std::function<void()> cb = nullptr;
            Fiber::ptr fiber;
        };

        int fd;
        Event events = NONE;
        Eventctx read;
        Eventctx write;
        MutexType fd_mutex;

        Eventctx& getEventctx(Event event);
        void triggerEvent(Event event);
    };

public:
    IOmanger(size_t threads=1, const std::string &name = "pool", bool debug = false);
    ~IOmanger();


public:
    IOmanger(const IOmanger&) = delete;
    IOmanger &operator=(const IOmanger&) = delete;

private:
    int m_epollfd = 0;
    int m_pipefd[2];
    std::vector<FdContext *> m_fdContexts;
    bool m_debug;
    RWMutexType m_mutex;
    std::atomic<size_t> m_pendingEventnum = {0};

private:
    void contextResize(const size_t size);

public:
    bool addEvent(int fd, Event event, std::function<void()> cb = nullptr);
    bool delEvent(int fd, Event event, bool istrig = true);
    bool delEventAll(int fd, bool istrig = true);
    size_t getEventnum();
    static IOmanger* GetThis();

protected:
    void v_idle() override;
    void v_ticked() override;
    void v_onTimerInsertedAtFront() override;
};

} // namespace learnco

#endif